Skip to content

FEATURE: Support all bbcode tags in the rich editor - #107

Open
renato wants to merge 3 commits into
mainfrom
rich-editor-extension
Open

FEATURE: Support all bbcode tags in the rich editor#107
renato wants to merge 3 commits into
mainfrom
rich-editor-extension

Conversation

@renato

@renato renato commented Aug 3, 2026

Copy link
Copy Markdown

Previously, opening a post that used any of this plugin's bbcode tags ([color], [size], [left], [list=a], etc.) in the rich text editor failed with "The rich text editor doesn't support all features used in this post" and forced the markdown editor.

This change adds a rich editor extension that parses and serializes every tag the plugin supports — inline styling as marks, alignment/indent/[ot]/[edit] as block nodes, and typed [list=X] lists — so bbcode posts open in the rich editor and keep cooking to the same output.

Each list item's content is now wrapped in hidden paragraph tokens, which render as nothing but let prosemirror-markdown's own list specs parse the item. Cooked sepquotes carry a data-tag, so [ot] and [edit] are told apart structurally instead of by their localized label.

Two things to note:

  • The source is normalized on a round trip: tags are lowercased, [li] items become [*], untyped [list]/[ul]/[ol] become markdown lists, a same-type tag nested in one with the same value drops out, and attribute quoting is canonicalized. Editing a bbcode post in the rich editor rewrites its source accordingly.
  • Content the editor can't represent exactly is declined instead, leaving the post to the markdown editor with its source intact: tag values outside the charsets the cook sanitizer allows, and a same-type tag nested in one with a differing value, since a mark set holds one mark per type and nested [size] percentages compound when cooked.

@ZogStriP ZogStriP left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💅

Opening a post that used any of this plugin's tags ([color], [size],
[left], [list=a], etc.) in the rich text editor failed with "The rich
text editor doesn't support all features used in this post" and forced
the markdown editor.

Add a rich editor extension covering every tag the plugin supports:
inline styling as marks, alignment, [indent], [ot] and [edit] as block
nodes, and typed [list=X] lists. A tag value is only accepted when it
matches the charsets the cook sanitizer allows, so the editor can't show
styling the rendered post drops, and a value can't carry extra style
declarations into the editor's DOM.

Content the editor can't represent exactly is declined rather than
rewritten, leaving the post to the markdown editor with its source
intact: values outside those charsets, and a same-type tag nested in one
with a differing value, since a mark set holds one mark per type and
nested [size] percentages compound when cooked.

Cooking changes with it, without changing what a post renders as. Cooked
sepquotes carry a data-tag, so [ot] and [edit] are told apart
structurally instead of by their localized label, which no longer works
once a post is read under another locale. Typed lists get their own token
type and every item's content is wrapped in hidden paragraph tokens,
which render as nothing but let prosemirror-markdown's own list specs
parse them.
@renato
renato force-pushed the rich-editor-extension branch from 7f0de84 to 407dff7 Compare August 5, 2026 18:13
renato added 2 commits August 6, 2026 12:38
Track whether an inline bbcode open token was ours, so its close ends
the mark we opened rather than whichever one happened to be on top. The
block wraps already did this; the inline path popped unconditionally.

Build the cook sanitizer's allowlist and the editor's value checks from
one set of charsets, so the two can't drift. The shared module sits
under discourse-markdown/ because only that path is loaded into the
server-side cooking context.

Guard the parse state reads that assumed a node was open, and say in a
comment why declining a token fails the parse.

Assert that a declined post leaves the editor empty rather than that it
renders no span, which a silently dropped tag would also satisfy, and
drop the round trip cases that restate an exact round trip already
asserted in the extension test.
A value needing quotes that contains every supported delimiter leaves
the serializer no pair to wrap it in, and its fallback strips the double
quotes. Round trip the value through the serializer and decline it when
it doesn't survive, rather than duplicating the delimiter list here.

The fidelity tests compared the cooked output of the editor's value
against the cooked source, which a declined parse satisfies on its own:
the editor is left empty and the value keeps the original markdown.
Assert the editor rendered something first.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants